﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Text;
using System.Net;
using System.Web;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml.Linq;
using System.IO;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace VideoSource
{


    public class VideoDataSource
    {
        static object objSync = new object();

        Dictionary<VideoItem, string> searchvideo = null;
        XDocument xdoc = null;
        DirectoryInfo basedir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + "XMLDB");

        public VideoDataSource()
        {
            if (basedir.Exists && basedir.GetFiles("DB*.xml", SearchOption.AllDirectories).Count() > 0)
            {
                lock (objSync)
                {
                    BuildLocalCache();
                    Thread t = new Thread(UpdateLocalXMLData);
                    t.Start();
                }
            }
            else
            {
                UpdateLocalXMLData();
                BuildLocalCache();
            }
        }

        public void BuildLocalCache()
        {
            searchvideo = new Dictionary<VideoItem, string>();

            foreach (var fileitem in basedir.GetFiles("DB*.xml", SearchOption.AllDirectories))
            {
                xdoc = XDocument.Parse(File.ReadAllText(fileitem.FullName));

                foreach (XElement xitem in xdoc.Descendants("Video"))
                {
                    string searchstring = string.Empty;

                    VideoItem vitem = new VideoItem()
                    {
                        Title = xitem.Element("Title").Value,
                        Description = xitem.Element("Description").Value,
                        URL = xitem.Element("URL").Value
                    };

                    searchstring += vitem.Title + " " + vitem.Description + " " + vitem.URL + " ";

                    vitem.TagList = new List<string>();

                    foreach (var item in xitem.Element("Tags").Elements("Tag"))
                    {
                        vitem.TagList.Add(item.Value);
                        searchstring += item.Value + " ";
                    }

                    lock (objSync)
                    {
                        searchvideo.Add(vitem, searchstring.ToLowerInvariant());
                    }
                }
            }
        }

        public void UpdateLocalXMLData()
        {
            try
            {
                if (basedir.Exists && basedir.GetFiles("DB*.xml", SearchOption.AllDirectories).Count() > 0)
                {
                    VerifyWithIndexAndDownloadXML();
                }
                else
                {
                    WebClient webclient = new WebClient();
                    webclient.Proxy.Credentials = WebRequest.GetSystemWebProxy().Credentials;
                    if (!basedir.Exists)
                        Directory.CreateDirectory(basedir.ToString());
                    basedir.Refresh();

                    string url = GetIndexURL(webclient);

                    if (!string.IsNullOrEmpty(url))
                    {
                        webclient.DownloadFile(url, basedir.FullName + "/" + "Index.xml");
                        XDocument xdocLocal = XDocument.Load(basedir.FullName + "\\" + "Index.xml");
                        foreach (XElement xitem in xdocLocal.Descendants("XML"))
                        {
                            string XMLDoc = xitem.Element("File").Value.ToString();
                            string URL = xitem.Element("URL").Value.ToString();
                            webclient.DownloadFile(URL, basedir.FullName + "/" + XMLDoc);
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                //Directory.Delete(basedir.ToString());
            }
        }

        private string GetIndexURL(WebClient webclient)
        {
            string indexurl = webclient.DownloadString("http://1video.codeplex.com/wikipage?title=IndexURL");
            indexurl = Regex.Match(indexurl, @"<div class=""wikidoc"">((.|)*?)</div>", RegexOptions.IgnoreCase).Value;
            return HttpUtility.HtmlDecode(Regex.Replace(indexurl, @"<div class=""wikidoc"">|</div>", "", RegexOptions.IgnoreCase));
        }

        public void VerifyWithIndexAndDownloadXML()
        {
            try
            {
                bool isIndexChanged = false;
                WebClient webclient = new WebClient();
                webclient.Proxy.Credentials = WebRequest.GetSystemWebProxy().Credentials;

                XDocument xdocLocal = XDocument.Load(basedir.FullName + "\\" + "Index.xml");

                string url = GetIndexURL(webclient);

                if (!string.IsNullOrEmpty(url))
                {
                    XDocument xdocOnline = XDocument.Load(url);

                    if (xdocOnline != null)
                    {
                        foreach (XElement xitem in xdocOnline.Descendants("XML"))
                        {
                            string LatestXMLDate = xitem.Element("File").Attribute("UpdateDate").Value.ToString();
                            string LatestXMLDoc = xitem.Element("File").Value.ToString();
                            string URL = xitem.Element("URL").Value.ToString();
                            bool isNewFile = true;

                            foreach (XElement xLocalItem in xdocLocal.Descendants("XML"))
                            {
                                string LocalXMLDate = xLocalItem.Element("File").Attribute("UpdateDate").Value.ToString();
                                string LocalXMLDoc = xLocalItem.Element("File").Value.ToString();

                                if (LatestXMLDoc == LocalXMLDoc)
                                {
                                    isNewFile = false;
                                    if (LatestXMLDate != LocalXMLDate)
                                    {
                                        //download the DATA file
                                        isIndexChanged = true;
                                        webclient.DownloadFile(
                                                   URL,
                                                    basedir.FullName + "/" + LocalXMLDoc);
                                        break;
                                    }

                                }

                            }
                            //download the new file that is uploaded 
                            if (isNewFile)
                            {
                                isIndexChanged = true;
                                webclient.DownloadFile(
                                           URL,
                                            basedir.FullName + "/" + LatestXMLDoc);

                            }
                        }

                        //download the INDEX file
                        if (isIndexChanged == true)
                        {
                            webclient.DownloadFile(
                                  url,
                                  basedir.FullName + "/" + "Index.xml");

                            BuildLocalCache();

                        }
                    }
                }
            }
            catch (Exception ex)
            {

            }

        }

        public ObservableCollection<VideoItem> GetVedioItemList(string keyword)
        {
            ObservableCollection<VideoItem> searchresult = new ObservableCollection<VideoItem>();
            if (searchvideo != null)
            {
                if (keyword.ToLowerInvariant() == "all")
                {
                    foreach (var item in searchvideo)
                    {
                        searchresult.Add(item.Key);
                    }
                }
                else
                {
                    foreach (var item in searchvideo.Where(p => p.Value.Contains(keyword.ToLowerInvariant())))
                    {
                        searchresult.Add(item.Key);
                    }
                }
            }
            return searchresult;
        }

    }
}
